﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;

namespace Jemgine.Engine.Renderer
{
    public class RenderEffect
    {
        public Texture2D LineTexture { get; private set; }
        public Texture2D SolidPointTexture { get; private set; }
        public Texture2D SolidShadowTexture { get; private set; }
        public Texture2D PenumbraShadowTexture { get; private set; }
        public String DrawLighted { get { return "DrawLighted"; } }
        public String DrawFullbright { get { return "DrawFullbright"; } }
        public String DrawFullbrightClamped { get { return "DrawFullbrightClamped"; } }

        private GraphicsDevice GraphicsDevice;
		Effect _effect;
		
		EffectParameter _viewMatrix;
        public Matrix ViewMatrix { set { _viewMatrix.SetValue(value); } }

		EffectParameter _projectionMatrix;
        public Matrix ProjectionMatrix { set { _projectionMatrix.SetValue(value); } }
        
        EffectParameter _worldMatrix;
        //public Matrix WorldMatrix { set { _worldMatrix.SetValue(value); } }
     
        EffectParameter _color;
        public Vector4 Color { set { _color.SetValue(value); } }
        
        EffectParameter _texture;
        public Texture2D Texture { set { _texture.SetValue(value); } }
        
        EffectParameter _shadowMap;
        public Texture2D ShadowMap { set { _shadowMap.SetValue(value); } }
        
        EffectParameter _lightMap;
        public Texture2D LightMap { set { _lightMap.SetValue(value); } }

        EffectParameter _tint;
        public Vector4 Tint { set { _tint.SetValue(value); } }

        public String Technique { private get; set; }


        private Stack<Matrix> MatrixStack = new Stack<Matrix>();

        public void PushMatrix(Matrix M)
        {
            MatrixStack.Push(M * MatrixStack.Peek());
            _worldMatrix.SetValue(TopMatrix);
        }

        public void PushCleanMatrix(Matrix M)
        {
            MatrixStack.Push(M);
            _worldMatrix.SetValue(TopMatrix);
        }

        public void PopMatrix()
        {
            if (MatrixStack.Count <= 1) throw new InvalidOperationException();
            MatrixStack.Pop();
            _worldMatrix.SetValue(TopMatrix);
        }

        public void RestoreMatrixStack()
        {
            MatrixStack.Clear();
            MatrixStack.Push(Matrix.Identity);
        }

        public Matrix TopMatrix { get { return MatrixStack.Peek(); } }

        public RenderEffect(GraphicsDevice GraphicsDevice, ContentManager Content)
        {
            reset(GraphicsDevice, Content);
        }

        public void reset(GraphicsDevice GraphicsDevice, ContentManager Content)
        {
            this.GraphicsDevice = GraphicsDevice;

            MatrixStack.Clear();
            MatrixStack.Push(Matrix.Identity);

			_effect = Content.Load<Effect>("Engine.Content/DefferredRenderer");
            LineTexture = Content.Load<Texture2D>("Engine.Content/line");
            SolidPointTexture = Content.Load<Texture2D>("Engine.Content/solidpoint");
            SolidShadowTexture = Content.Load<Texture2D>("Engine.Content/solidshadow");
            PenumbraShadowTexture = Content.Load<Texture2D>("Engine.Content/penumbra");

			_viewMatrix = _effect.Parameters["View"];
			_projectionMatrix = _effect.Parameters["Projection"];
			_worldMatrix = _effect.Parameters["World"];
			_color = _effect.Parameters["Color"];
			_texture = _effect.Parameters["Texture"];
            _shadowMap = _effect.Parameters["ShadowMap"];
            _lightMap = _effect.Parameters["LightMap"];
            _tint = _effect.Parameters["Tint"];

            Color = Vector4.One;
        }

        public void Apply()
        {
            _worldMatrix.SetValue(TopMatrix);
            _effect.CurrentTechnique = _effect.Techniques[Technique];
            _effect.CurrentTechnique.Passes[0].Apply();
        }
    }
}
